package com.example.high_slope_electronic_sand_table.slopeMechanics.service;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.example.high_slope_electronic_sand_table.common.constant.DataClassificationConstant;
import com.example.high_slope_electronic_sand_table.common.constant.GeneralConstants;
import com.example.high_slope_electronic_sand_table.common.util.WeightRandomUtil;
import com.example.high_slope_electronic_sand_table.slopeMechanics.Enum.SupportStructureStrainWarningEnum;
import com.example.high_slope_electronic_sand_table.slopeMechanics.Enum.SupportStructureStressWarningEnum;
import com.example.high_slope_electronic_sand_table.slopeMechanics.dto.SupportStructureMonitorDTO;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SupportStructureMonitorService {
    private final static String DEVICE_SN_MIDDLE= "0SMM0"; // 设备编码中段

    private final static Integer MAX_SIZE = 30; // 最大数据条数

    private static Map<String, List<SupportStructureMonitorDTO>> slopeMechanicsMonitorDataMap = new HashMap<>();

    /**
     * 查询单条边坡力学监测-支护结构数据
     *
     * @return
     */
    public SupportStructureMonitorDTO getCurrentMonitorData(String deviceId) {
        if (!slopeMechanicsMonitorDataMap.containsKey(deviceId) || slopeMechanicsMonitorDataMap.get(deviceId).isEmpty()) {
            batchGeneratorMonitorDataS(deviceId);
        }
        // 获取当前的时间和当前设备数据最后一条时间比较，如果当前时间比数据最后一条时间大于等于10分钟，则重新生成一条数据放在列表最后。如果小于十分钟，返回最后一条数据
        LocalDateTime currentDateTime = LocalDateTime.now();
        SupportStructureMonitorDTO slopeMechanicsMonitorDTO = slopeMechanicsMonitorDataMap.get(deviceId).get(MAX_SIZE - 1);
        LocalDateTime lastDateTime = LocalDateTime.parse(slopeMechanicsMonitorDTO.getDatetime(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
        Duration duration = Duration.between(lastDateTime, currentDateTime);
        if (duration.toMinutes() >= GeneralConstants.GENERATOR_DATA_DURATION_TIME) {
            for (int item = 1; item <= duration.toMinutes() / GeneralConstants.GENERATOR_DATA_DURATION_TIME; item++) {
                 Date newDate = DateUtil.offset(Date.from(lastDateTime.atZone(ZoneId.systemDefault()).toInstant()), DateField.MINUTE, +item * GeneralConstants.GENERATOR_DATA_DURATION_TIME); // 最后一条时间向后推10分钟
                slopeMechanicsMonitorDataMap.get(deviceId).add(generatorMonitorData(deviceId, DateUtil.format(newDate, DatePattern.NORM_DATETIME_PATTERN)));
                slopeMechanicsMonitorDataMap.get(deviceId).remove(0);
            }
            return slopeMechanicsMonitorDataMap.get(deviceId).get(MAX_SIZE - 1);
        } else {
            return slopeMechanicsMonitorDTO;
        }
    }

    /**
     * 查询某个设备所有边坡力学监测-支护结构数据
     *
     * @return
     */
    public List<SupportStructureMonitorDTO> listMonitorDataByDeviceId(@PathVariable String deviceId) {
        if (!slopeMechanicsMonitorDataMap.containsKey(deviceId) || slopeMechanicsMonitorDataMap.get(deviceId).isEmpty()) {
            batchGeneratorMonitorDataS(deviceId);
        }
        return slopeMechanicsMonitorDataMap.get(deviceId).stream().sorted(Comparator.comparing(SupportStructureMonitorDTO::getDatetime).reversed()).collect(Collectors.toList());
    }

    /**
     * 查询某个设备所有边坡力学监测-支护结构告警数据
     *
     * @return
     */
    public List<SupportStructureMonitorDTO> listWarningMonitorDataByDeviceId(@PathVariable String deviceId) {
        if (!slopeMechanicsMonitorDataMap.containsKey(deviceId) || slopeMechanicsMonitorDataMap.get(deviceId).isEmpty()) {
            batchGeneratorMonitorDataS(deviceId);
        }
        return slopeMechanicsMonitorDataMap.get(deviceId)
                .stream().sorted(Comparator.comparing(SupportStructureMonitorDTO::getDatetime).reversed())
                .filter(slopeMechanicsMonitorDTO -> slopeMechanicsMonitorDTO.getSupportStructureStrainWarningLevel() != 0
                                || slopeMechanicsMonitorDTO.getSupportStructureStressWarningLevel() != 0)
                .collect(Collectors.toList());
    }


    /**
     * 查询多条边坡力学监测-支护结构数据
     *
     * @return
     */
    public List<SupportStructureMonitorDTO> listMonitorData() {
        List<SupportStructureMonitorDTO> slopeMechanicsMonitorDTOS = new ArrayList<>();
        if (slopeMechanicsMonitorDataMap.isEmpty()){
            // 生成3个设备相关数据
            for (int index = 0; index < GeneralConstants.GENERATOR_DEVICE_NUMBER ; index ++){
                String deviceId = GeneralConstants.DEVICE_SN_PREFIX + DEVICE_SN_MIDDLE + index;
                batchGeneratorMonitorDataS(deviceId);
            }
        }
        for (String deviceId : slopeMechanicsMonitorDataMap.keySet()) {
            slopeMechanicsMonitorDTOS.addAll(slopeMechanicsMonitorDataMap.get(deviceId));
        }
        return slopeMechanicsMonitorDTOS.stream().sorted(Comparator.comparing(SupportStructureMonitorDTO::getDatetime).reversed()).collect(Collectors.toList());
    }

    /**
     * 批量生成边坡力学监测-支护结构数据
     *
     * @param deviceId
     */
    private void batchGeneratorMonitorDataS(String deviceId) {
        List<SupportStructureMonitorDTO> slopeMechanicsMonitorDTOS = new ArrayList<>(MAX_SIZE);
        for (int item = 1; item <= MAX_SIZE; item++) {
            Date date = DateUtil.date();
            Date newDate = DateUtil.offset(date, DateField.MINUTE, -(MAX_SIZE - item) * GeneralConstants.GENERATOR_DATA_DURATION_TIME); // 当前时间向前推item*10分钟
            slopeMechanicsMonitorDTOS.add(generatorMonitorData(deviceId, DateUtil.format(newDate, DatePattern.NORM_DATETIME_PATTERN)));
        }
        slopeMechanicsMonitorDataMap.put(deviceId, slopeMechanicsMonitorDTOS);
    }

    /**
     * 生成边坡力学监测-支护结构数据
     * 
     * @param deviceId
     * @param dateTime
     * @return
     */
    private SupportStructureMonitorDTO generatorMonitorData(String deviceId, String dateTime){
        SupportStructureMonitorDTO slopeMechanicsMonitorDTO = new SupportStructureMonitorDTO();
        slopeMechanicsMonitorDTO.setDeviceId(deviceId);
        Float supportStructureStressValue = WeightRandomUtil.getWeightRandomValue(SupportStructureStressWarningEnum.WARNING_ONE.getValue(),
                SupportStructureStressWarningEnum.WARNING_TWO.getValue(), SupportStructureStressWarningEnum.WARNING_THREE.getValue(),
                0f, 10f);
        slopeMechanicsMonitorDTO.setSupportStructureStress(supportStructureStressValue);
        Float supportStructureStrainValue = WeightRandomUtil.getWeightRandomValue(SupportStructureStrainWarningEnum.WARNING_ONE.getValue(),
                SupportStructureStrainWarningEnum.WARNING_TWO.getValue(), SupportStructureStrainWarningEnum.WARNING_THREE.getValue(),
                0f, 0.2f);
        slopeMechanicsMonitorDTO.setSupportStructureStrain(supportStructureStrainValue);
//        slopeMechanicsMonitorDTO.setSupportStructureStress(RandomUtil.randomFloat(0f, 10f));
//        slopeMechanicsMonitorDTO.setSupportStructureStrain(RandomUtil.randomFloat(0f, 0.2f));
        slopeMechanicsMonitorDTO.setDatetime(dateTime);
        checkWarningLevel(slopeMechanicsMonitorDTO);
        return slopeMechanicsMonitorDTO;
    }

    /**
     * 判断告警等级
     *
     * @param slopeMechanicsMonitorDTO
     */
    private void checkWarningLevel(SupportStructureMonitorDTO slopeMechanicsMonitorDTO) {
        // 支护结构-应力
        Optional<SupportStructureStressWarningEnum> supportStructureStressFirst = DataClassificationConstant.supportStructureStressWarningList.stream()
                .filter(supportStructureStressWarning -> slopeMechanicsMonitorDTO.getSupportStructureStress() >= supportStructureStressWarning.getValue())
                .findFirst();
        slopeMechanicsMonitorDTO.setSupportStructureStressWarningLevel(
                supportStructureStressFirst.isEmpty() || ObjectUtil.isEmpty(supportStructureStressFirst.get()) ? 0 : supportStructureStressFirst.get().getWarningLevel());
        // 支护结构-应变
        Optional<SupportStructureStrainWarningEnum> supportStructureStrainFirst = DataClassificationConstant.supportStructureStrainWarningList.stream()
                .filter(supportStructureStrainWarning -> slopeMechanicsMonitorDTO.getSupportStructureStrain() >= supportStructureStrainWarning.getValue())
                .findFirst();
        slopeMechanicsMonitorDTO.setSupportStructureStrainWarningLevel(
                supportStructureStrainFirst.isEmpty() || ObjectUtil.isEmpty(supportStructureStrainFirst.get()) ? 0 : supportStructureStrainFirst.get().getWarningLevel());
    }
}
